import 'dart:math';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

import 'bezier_util.dart';

class BezierAnimationDemo extends StatefulWidget {
  BezierAnimationDemo({Key? key}) : super(key: key);

  @override
  State<BezierAnimationDemo> createState() => _BezierAnimationDemoState();
}

class _BezierAnimationDemoState extends State<BezierAnimationDemo>
    with SingleTickerProviderStateMixin {
  late Animation<double> animation;
  late AnimationController controller;

  @override
  void initState() {
    super.initState();
    controller =
        AnimationController(duration: const Duration(seconds: 1), vsync: this);
    animation = Tween<double>(begin: 0, end: 1.0)
        .animate(CurvedAnimation(parent: controller, curve: Curves.easeInCubic))
      ..addListener(() {
        setState(() {});
      });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text('贝塞尔动画'),
          systemOverlayStyle: SystemUiOverlayStyle.light,
          backgroundColor: Colors.black87,
        ),
        body: CustomPaint(
          foregroundPainter: AnimationBezierPainter(
            animationValue: animation.value,
          ),
          child: Container(
            width: MediaQuery.of(context).size.width,
            height: MediaQuery.of(context).size.height,
            color: Color.fromARGB(255, 55, 185, 236),
          ),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            // if (controller.status == AnimationStatus.completed) {
            //   controller.reverse();
            // } else {
            //   controller.forward();
            // }
            controller.repeat(min: 0.5, max: 1.0, reverse: true);
          },
          child: Icon(
            Icons.play_arrow,
          ),
        ));
  }
}

class AnimationBezierPainter extends CustomPainter {
  AnimationBezierPainter({required this.animationValue});
  final double animationValue;
  @override
  void paint(Canvas canvas, Size size) {
    //canvas.drawColor(Color(0xFFF1F1F1), BlendMode.color);
    var paint = Paint()..color = Colors.black54;
    final lineWidth = 2.0;
    paint.strokeWidth = lineWidth;
    paint.style = PaintingStyle.stroke;
    final colors = [
      Color(0xFFE05100),
      Color(0xFFF0A060),
      Color(0xFFE0E000),
      Color(0xFF10F020),
      Color(0xFF2080F5),
      Color(0xFF104FF0),
      Color(0xFFA040E5),
    ];

    final lineNumber = 20;
    //3D飞行效果，请使用 repeat 模式
    // for (var i = 0; i < lineNumber; ++i) {
    //   _drawFlying(canvas, paint, size, size.width * i / lineNumber);
    // }

    // 弹簧效果
    final yGap = 2.0 + 16.0 * animationValue;
    for (var i = 0; i < (lineNumber * animationValue).toInt(); ++i) {
      _drawSpiralLines(
          canvas, paint, size, size.width / 2, size.height - i * yGap, yGap);
    }

    // 彩虹效果
    //   for (var i = 0; i < lineNumber; ++i) {
    //     paint.color = colors[i % colors.length];
    //     _drawRainbowLines(canvas, paint, size, size.height / 4 + i * lineWidth);
    //   }
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return true;
  }

  _drawRainbowLines(Canvas canvas, Paint paint, Size size, yPos) {
    var yGap = 60.0;
    var p0 = Offset(0, yPos);
    var p1 = Offset(size.width * 2 / 3, yPos - yGap);
    var p2 = Offset(size.width * 2 / 3, yPos + yGap);
    var p3 = Offset(size.width / 3, yPos + yGap);
    var path = Path();
    path.moveTo(p0.dx, p0.dy);
    for (var t = 1; t <= (100 * animationValue).toInt(); t += 1) {
      var curvePoint =
          BezierUtil.get3OrderBezierPoint(p0, p1, p2, p3, t / 100.0);

      path.lineTo(curvePoint.dx, curvePoint.dy);
    }
    canvas.drawPath(path, paint);
  }

  _drawSpiralLines(Canvas canvas, Paint paint, Size size, double xPos,
      double yPos, double yGap) {
    final xWidth = 160.0;
    var p0 = Offset(xPos, yPos);
    var p1 = Offset(xPos + xWidth / 2 + xWidth / 4, yPos - yGap);
    var p2 = Offset(xPos + xWidth / 2 - xWidth / 4, yPos - 3 * yGap);
    var p3 = Offset(xPos, yPos - yGap);
    var path = Path();
    path.moveTo(p0.dx, p0.dy);
    for (var t = 1; t <= 100; t += 1) {
      var curvePoint =
          BezierUtil.get3OrderBezierPoint(p0, p1, p2, p3, t / 100.0);

      path.lineTo(curvePoint.dx, curvePoint.dy);
    }
    canvas.drawPath(path, paint);
  }

  _drawFlying(Canvas canvas, Paint paint, Size size, double xGap) {
    final yPos = size.height * 3 / 4 + size.height * animationValue / 4;
    final yStep = 20.0 * animationValue;
    var xPos = size.width / 2;
    var p0 = Offset(xPos, size.height * 6 / 8 - yStep);
    var p1 = Offset(xPos + xGap / 4, size.height - yPos / 4 - yStep);
    var p2 = Offset(xPos - xGap / 2, size.height - yPos / 8 - yStep);
    var p3 = Offset(size.width / 4, yPos - yStep);
    var path = Path();
    path.moveTo(p0.dx, p0.dy);
    for (var t = 1; t <= 100; t += 1) {
      var curvePoint =
          BezierUtil.get3OrderBezierPoint(p0, p1, p2, p3, t / 100.0);

      path.lineTo(curvePoint.dx, curvePoint.dy);
    }
    canvas.drawPath(path, paint);

    p0 = Offset(xPos, size.height * 6 / 8 - yStep);
    p1 = Offset(xPos - xGap / 4, size.height - yPos / 4 - yStep);
    p2 = Offset(xPos + xGap / 2, size.height - yPos / 8 - yStep);
    p3 = Offset(size.width * 3 / 4, yPos - yStep);
    var path2 = Path();
    path2.moveTo(p0.dx, p0.dy);
    for (var t = 1; t <= 100; t += 1) {
      var curvePoint =
          BezierUtil.get3OrderBezierPoint(p0, p1, p2, p3, t / 100.0);

      path2.lineTo(curvePoint.dx, curvePoint.dy);
    }
    canvas.drawPath(path2, paint);

    p0 = Offset(size.width / 2, size.height * 6 / 8);
    p1 = Offset(xPos + xGap / 8, size.height - yPos / 4 - yStep);
    p2 = Offset(xPos - xGap / 4 + 15, size.height - yPos / 8 - yStep);
    p3 = Offset(size.width / 2, yPos - yStep);
    var path3 = Path();
    path3.moveTo(p0.dx, p0.dy);
    for (var t = 1; t <= 100; t += 1) {
      var curvePoint =
          BezierUtil.get3OrderBezierPoint(p0, p1, p2, p3, t / 100.0);

      path3.lineTo(curvePoint.dx, curvePoint.dy);
    }
    canvas.drawPath(path3, paint);

    p0 = Offset(size.width / 2, size.height * 6 / 8);
    p1 = Offset(xPos - xGap / 8, size.height - yPos / 4 - yStep);
    p2 = Offset(xPos + xGap / 4 - 15, size.height - yPos / 8 - yStep);
    p3 = Offset(size.width / 2, yPos - yStep);
    var path4 = Path();
    path4.moveTo(p0.dx, p0.dy);
    for (var t = 1; t <= 100; t += 1) {
      var curvePoint =
          BezierUtil.get3OrderBezierPoint(p0, p1, p2, p3, t / 100.0);

      path4.lineTo(curvePoint.dx, curvePoint.dy);
    }
    canvas.drawPath(path4, paint);
  }
}

class SineCurve extends Curve {
  final int count;
  const SineCurve({this.count = 1}) : assert(count > 0);

  @override
  double transformInternal(double t) {
    // 需要补偿pi/2个角度，使得起始值是0.终止值是1，避免出现最后突然回到0
    return sin(2 * (count + 0.25) * pi * t);
  }
}
